module cpu(reset, clock, write_read, M_address,M_data_in, M_data_out,overflow,status);
 input reset,clock;
 input[7:0] M_data_in;
 output reg write_read,overflow;
 output reg [7:0] M_data_out;
 output reg[11:0] M_address;
 reg flag; //标志是否溢出
 reg[15:0] IR;
 reg[7:0] MDR;
 reg[11:0] MAR,PC;
 reg[7:0] A,R0,R1,R2,R3,RX;
 reg[8:0] RZ;
 output reg[2:0] status;
 parameter idle=4'b0000, load=4'b0001, move=4'b0010, add=4'b0011, sub=4'b0100, AND=4'b0101, OR=4'b0110, XOR=4'b0111,
           shrp=4'b1000, shlp=4'b1001, swap=4'b1010, jmp=4'b1011, jz=4'b1100, read=4'b1101, write=4'b1110, stop=4'b1111;//指令操作码
			  
always@(reset or status) // process the read and write operation for main memory. 
begin
 if((reset==1)&&(status==3)&&(IR[15:12]==write)) 
	write_read=1'b1;//write opeartion
 else
	write_read=1'b0;//read operation
 M_address=MAR;
 M_data_out=MDR;
 //overflow标志位的处理，overflow仅在进行加、减运算时才可能为1.
 if((IR[15:12]==add||IR[15:12]==sub)&&flag==1&&(reset==1)&&(status==1))
	overflow=1'b1;
 else overflow=1'b0;
end
 
always @(negedge clock or negedge reset)// status_change process, status machine 
begin
 if(reset==1'b0) begin MAR<=12'd0;A<=8'd0;status<=3'b000; end// valid reset signal is 0 
 else if(clock==1'b0)// descend edge of clock 
 case (status)
 3'b000: 
 begin
	status<=1; 
	MAR<=PC;
	case(IR[9:8])
		2'b00: A<=R0;
		2'b01: A<=R1;
		2'b10: A<=R2;
		2'b11: A<=R3;
	endcase
 end 
 3'b001: 
 begin
	if(IR[15:12]==stop) status<=1;
	else if ((IR[15:12]==swap)|| (IR[15:12]==jmp)||(IR[15:12]==jz)||(IR[15:12]==read)||(IR[15:12]==write)) status<=2;
	else status<=0;
 end
 3'b010:
 begin 
	if(IR[15:12]==swap) status<=0;
	else status<=3; 
	if ((IR[15:12]==jmp)||(IR[15:12]==read)||(IR[15:12]==write))
		MAR <= IR[11:0];
	else if(IR[15:12]==jz&&R0[7:0] == 8'd0)//条件转移
		MAR <= IR[11:0];
	else
		MAR <= PC;
 end
 3'b011:
 begin
	if((IR[15:12]==jmp)||(IR[15:12]==jz))
		status<=0;
	else status<=4;
	if((IR[15:12]==read)||(IR[15:12]==write))
		MAR=PC;
 end
 3'b100:
		status<=0;
 endcase
end

always@(posedge clock or negedge reset)//process each status of each instruction 
begin
 if(reset==1'b0) 
 begin
	IR<=16'd0;
	PC<=12'd0;
	MDR<=8'd0; //reset operation
	R0<=8'd0;
	R1<=8'd0;
	R2<=8'd0;
	R3<=8'd0;	
	RX<=8'd0;
	RZ<=9'd0;
 end
 else if (clock==1'b1)
 begin
	case (status)
	3'b000:  // status 0, fetch instruction
	 begin
		IR<={M_data_in,8'b00000000}; 
		PC<=PC+1;
	 end
	3'b001: 
	begin //status 1
	 case(IR[15:12])//IR[15:12] is op segment
		load:R0<={4'b0000,IR[11:8]}; 
		move:
		begin
			case(IR[11:10])
			2'b00: R0<=A;
			2'b01: R1<=A;
			2'b10: R2<=A;
			2'b11: R3<=A;
			endcase
		end
		add:
		begin
			case(IR[11:10])
			2'b00: begin RX<=R0;R0<=R0+A; end
			2'b01: begin RX<=R1;R1<=R1+A; end
			2'b10: begin RX<=R2;R2<=R2+A; end
			2'b11: begin RX<=R3;R3<=R3+A; end
			endcase
			RZ={RX[7],RX}+{A[7],A};
			if(RZ[8]!=RZ[7])
				flag<=1'b1;
			else
				flag<=1'b0;
		end
		sub:
		begin
			case(IR[11:10])
			2'b00: begin RX<=R0;R0<=R0-A; end
			2'b01: begin RX<=R1;R1<=R1-A; end
			2'b10: begin RX<=R2;R2<=R2-A; end
			2'b11: begin RX<=R3;R3<=R3-A; end
			endcase
			RZ={RX[7],RX}-{A[7],A};
			if(RZ[8]!=RZ[7])
				flag<=1'b1;
			else
				flag<=1'b0;
		end
		AND:
		begin
			case(IR[11:10])
			2'b00: R0<=R0&A;
			2'b01: R1<=R1&A;
			2'b10: R2<=R2&A;
			2'b11: R3<=R3&A;
			endcase
		end
		OR:
		begin
			case(IR[11:10])
			2'b00: R0<=R0|A;
			2'b01: R1<=R1|A;
			2'b10: R2<=R2|A;
			2'b11: R3<=R3|A;
			endcase
		end
		XOR:
		begin
			case(IR[11:10])
			2'b00: R0<=R0^A;
			2'b01: R1<=R1^A;
			2'b10: R2<=R2^A;
			2'b11: R3<=R3^A;
			endcase
		end
		shlp:
		begin
			case(IR[11:10]) 
				2'b00:R0<=R0<<1;
				2'b01:R1<=R1<<1;
				2'b10:R2<=R2<<1;
				2'b11:R3<=R3<<1;
			endcase
		end 
		shrp:
		begin
			case(IR[11:10]) 
				2'b00:R0<=R0>>1;
				2'b01:R1<=R1>>1;
				2'b10:R2<=R2>>1;
				2'b11:R3<=R3>>1;
			endcase
		end 
		swap:
		begin
			case(IR[11:10]) 
				2'b00:RX<=R0;
				2'b01:RX<=R1;
				2'b10:RX<=R2;
				2'b11:RX<=R3;
			endcase
			case(IR[9:8]) 
				2'b00:R0<=RX;
				2'b01:R1<=RX;
				2'b10:R2<=RX;
				2'b11:R3<=RX;
			endcase
			case(IR[9:8])
				2'b00:
					case(IR[11:10])
					2'b00:R0<=R0;
					2'b01:R0<=R1;
					2'b10:R0<=R2;
					2'b11:R0<=R3;
					endcase
				2'b01:
					case(IR[11:10])
					2'b00:R1<=R0;
					2'b01:R1<=R1;
					2'b10:R1<=R2;
					2'b11:R1<=R3;
					endcase
				2'b10:
					case(IR[11:10])
					2'b00:R2<=R0;
					2'b01:R2<=R1;
					2'b10:R2<=R2;
					2'b11:R2<=R3;
					endcase
				2'b11:
					case(IR[11:10])
					2'b00:R3<=R0;
					2'b01:R3<=R1;
					2'b10:R3<=R2;
					2'b11:R3<=R3;
					endcase
		 endcase
		end 
	 endcase
 
	end
	3'b010: 
	begin
	 if(IR[15:12]==swap)
			case(IR[11:10]) 
				2'b00:R0<=A;
				2'b01:R1<=A;
				2'b10:R2<=A;
				2'b11:R3<=A;
			endcase
	 else if((IR[15:12]==jmp)||(IR[15:12]==read)||(IR[15:12]==jz))
	 begin 
		PC<=PC+1;	
		IR[7:0]=M_data_in;
	 end
	 else if(IR[15:12]==write)
	 begin 
		PC<=PC+1;	
		MDR=R0;
		IR[7:0]=M_data_in;	 
	 end
	end 
	3'b011:
	begin
	 if(IR[15:12]==jmp) 
			PC<=IR[11:0];
	 else if((IR[15:12]==jz)&&R0==0)
			PC<=IR[11:0]; 
	end
	3'b100:
	begin 
	 if(IR[15:12]==read) 
			R0<=M_data_in;
	end
	endcase
 end
end 
endmodule 